﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Tools.DllImport;
using System.Runtime.InteropServices;

namespace System.Tools.Hook.Mouse
{
    [StructLayout(LayoutKind.Sequential)]
    public struct POINT
    {
        public int x;
        public int y;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct MSLLHOOKSTRUCT
    {
        public POINT pt;
        public uint mouseData;
        public uint flags;
        public uint time;
        public IntPtr dwExtraInfo;
    }

    public class HookMouseEvent:EventArgs
    {
         public int wParam;
         public MSLLHOOKSTRUCT lParam;

         public HookMouseEvent(int wParam, MSLLHOOKSTRUCT lParam)
         {
             this.wParam = wParam;
             this.lParam = lParam;
         }

    }

    public class HookMouse
    {      
        const int WH_KEYBOARD_LL = 13;    // Номер глобального LowLevel-хука на клавиатуру
        const int WH_MOUSE_LL    = 14;    // Номер глобального LowLevel-хука на мышку
        const int WM_KEYDOWN     = 0x100; // Сообщения нажатия клавиши
        const int WM_KEYUP       = 0x100; // Сообщения нажатия клавиши

        const int WM_LBUTTONDOWN = 0x0201;
        const int WM_LBUTTONUP   = 0x0202;
        const int WM_MOUSEMOVE   = 0x0200;
        const int WM_MOUSEWHEEL  = 0x020A;
        const int WM_RBUTTONDOWN = 0x0204;
        const int WM_RBUTTONUP   = 0x0205;

        public static event EventHandler<HookMouseEvent> OnHook;

        public static event EventHandler<HookMouseEvent> OnLBUTTONDOWN;
        public static event EventHandler<HookMouseEvent> OnLBUTTONUP;
        public static event EventHandler<HookMouseEvent> OnMOUSEMOVE;
        public static event EventHandler<HookMouseEvent> OnMOUSEWHEEL;
        public static event EventHandler<HookMouseEvent> OnRBUTTONDOWN;
        public static event EventHandler<HookMouseEvent> OnRBUTTONUP;

        private static User32.HookProc proc = hookProc;
        private static IntPtr hhook = IntPtr.Zero;

        public static void SetHook()
        {
            // Получаем handle нужной библиотеки
            IntPtr hInstance = Kernel32.LoadLibrary("User32");

            // Ставим LowLevel-hook, обработки клавиатуры, на все потоки
            hhook = User32.SetWindowsHookEx(WH_MOUSE_LL, proc, hInstance, 0);
        }

        public static void UnHook()
        {
            // Снятие хука
            User32.UnhookWindowsHookEx(hhook);
        }

        public static IntPtr hookProc(int code, IntPtr wParam, IntPtr lParam)
        {            
            try
            {
                if (code == 0)
                {
                    MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
                    int vkParam = (int)wParam;

                    if (OnHook != null) { OnHook(null, new HookMouseEvent(vkParam, hookStruct)); }

                    if (vkParam == WM_LBUTTONDOWN)
                    {
                        if (OnLBUTTONDOWN != null) { OnLBUTTONDOWN(null, new HookMouseEvent(vkParam, hookStruct)); }
                    }
                    if (vkParam == WM_LBUTTONUP)
                    {
                        if (OnLBUTTONUP != null) { OnLBUTTONUP(null, new HookMouseEvent(vkParam, hookStruct)); }
                    }
                    if (vkParam == WM_MOUSEMOVE)
                    {
                        if (OnMOUSEMOVE != null) { OnMOUSEMOVE(null, new HookMouseEvent(vkParam, hookStruct)); }
                    }
                    if (vkParam == WM_MOUSEWHEEL)
                    {
                        if (OnMOUSEWHEEL != null) { OnMOUSEWHEEL(null, new HookMouseEvent(vkParam, hookStruct)); }
                    }
                    if (vkParam == WM_RBUTTONDOWN)
                    {
                        if (OnRBUTTONDOWN != null) { OnRBUTTONDOWN(null, new HookMouseEvent(vkParam, hookStruct)); }
                    }
                    if (vkParam == WM_RBUTTONUP)
                    {
                        if (OnRBUTTONUP != null) { OnRBUTTONUP(null, new HookMouseEvent(vkParam, hookStruct)); }
                    }
                }
            }
            catch
            { 

            }
            finally
            {
                
            }

            return User32.CallNextHookEx(hhook, code, (int)wParam, lParam);       
        }
    }
}
